//  Author:
//       Daniel Großer <olav.daniel.grosser@googlemail.com>
//  
//  Copyright (c) 2012 Copyright (C) 2012 by Daniel Großer. This Code is under GNU LGPL 3.0
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Reflection;
using System.IO;
using System.ComponentModel;
using Beauty.Contract;
using Beauty.ErrorHandling;
using System.Text;

namespace Beauty
{
    /// <summary>
    /// This is the core class of Beauty. The parser takes the input and converts it into an AST
    /// where your classes will be used to form the AST for a LL(1) language.
    /// </summary>
    public sealed class Parser : IProduceEBNF
    {
        /// <summary>
        /// Create a new parser. The parser derives the language grammar from your classes that act as AST nodes plus
        /// the attributes attached to the public properties of these classes. The parser only works with LL(1)
        /// languages.
        /// </summary>
        /// <param name="language">The language defined by the <see cref="INode"/> implementations. You could use the <see cref="AssemblyLanguageProvider"/> or <see cref="NamespaceLanguageProvider"/> or a custom implementation.</param>
        public Parser(ILanguageProvider language)
        {
            Productions = new Dictionary<Type, Production>();

            foreach (Type production in language.AbstractSyntaxTreeNodes)
                Productions.Add(production, new Production(this, production));

			var allTerminals = new HashSet<TerminalAttribute>();

			// Calculate the expected terminals and total terminals.
			// This would detect all kinds of grammar errors early.
            foreach (Production production in Productions.Values)
            {
				production.CalculateTerminals(allTerminals);
                var expectedTerminals = production.ExpectedTerminals;
            }
		
			_Terminals = allTerminals.ToList();
			
        }

        /// <summary>
        /// The set of productions, that is, the LL(1) grammar derived from your classes
        /// </summary>
        private readonly Dictionary<Type, Production> Productions;
		
		private readonly ICollection<TerminalAttribute> _Terminals;
		/// <summary>
		/// Gets the set of all terminals.
		/// </summary>
		/// <value>
		/// The terminals.
		/// </value>
		public ICollection<TerminalAttribute> Terminals { get { return _Terminals; } }

        /// <summary>
        /// This is the main method. The default scanner will be used to scan the input. The default scanner
        /// works on a per-line basis and does not allow your terminals to cross line-boundaries, plus, it does not
        /// make use of white-spaces (which all languages except Whitespace do...).
        /// </summary>
        /// <typeparam name="RootT">The type of AST node to return, that is, the root of the program/grammer (so-called starting symbol).</typeparam>
        /// <param name="input">The input to parse.</param>
        /// <returns>The parsed node on success.</returns>
        public RootT Parse<RootT>(String input) where RootT : INode
        {
            return Parse<RootT>(new StringReader(input));
        }

        /// <summary>
        /// This is the main method. The default scanner will be used to scan the input. The default scanner
        /// works on a per-line basis and does not allow your terminals to cross line-boundaries, plus, it does not
        /// make use of white-spaces (which all languages except Whitespace do...).
        /// </summary>
        /// <typeparam name="RootT">The type of AST node to return, that is, the root of the program/grammer (so-called starting symbol).</typeparam>
        /// <param name="input">The input to parse.</param>
        /// <returns>The parsed node on success.</returns>
        public RootT Parse<RootT>(TextReader input) where RootT : INode
        {
            var scanner = new Tools.Scanner(input);
            return Parse<RootT>(scanner);
        }

        /// <summary>
        /// Parse the AST from the input through a custom scanner.
        /// </summary>
        /// <typeparam name="RootT">The type of AST node to return, that is, the root of the program/grammer (so-called starting symbol).</typeparam>
        /// <param name="scanner">The scanner instance to use.</param>
        /// <returns>The parsed node on success.</returns>
        public RootT Parse<RootT>(IScanner scanner) where RootT : INode
        {
			scanner.Setup(Terminals);
            var result = (RootT)this[typeof(RootT)].Parse(scanner, null);
            if (!scanner.EOF)
                throw new ParserException(scanner, ParserErrorType.Expected_EOF);
            return result;
        }

        /// <summary>
        /// Get the EBNF form of the grammer recognized by the parser.
        /// </summary>
        public string EBNF
        {
            get
            {
                StringBuilder result = new StringBuilder();
                foreach (var production in Productions.Values)
                    result.AppendLine(production.EBNF);
                return result.ToString();
            }
        }

        /// <summary>
        /// Get the production for a certain type.
        /// </summary>
        /// <param name="typeToProduce">The type to get the production for.</param>
        /// <returns>The production.</returns>
        private Production this[Type typeToProduce]
        {
            get
            {
                if (!Productions.ContainsKey(typeToProduce))
                    throw new ParserException(ParserErrorType.AST_NotInLanguage, typeToProduce);
                else return Productions[typeToProduce];
            }
        }

        /// <summary>
        /// Get all productions that would possibly apply for an abstract type.
        /// </summary>
        /// <param name="typeToProduce">The abstract type that serves as alternation.</param>
        /// <returns>The productions that are possible.</returns>
        private ICollection<Production> AlternationsOf(Type typeToProduce)
        {
            // Select all Productions that could produce an instance of the passed type.
            var result = new List<Production>(Productions.Where((rule)=>rule.Value.CanServeAlternation(typeToProduce)).Select((kvp)=>kvp.Value));
            return result;
        }

        /// <summary>
        /// This is an abstract base class for entities that are "owned" by other entities.
        /// </summary>
        /// <typeparam name="T">The type of the owner.</typeparam>
        abstract class OwnedItem<T>
        {
            /// <summary>
            /// Create a new instance.
            /// </summary>
            /// <param name="owner">The owning entity.</param>
            protected OwnedItem(T owner)
            {
                Owner = owner;
            }

            /// <summary>
            /// Get the owning entity.
            /// </summary>
            public T Owner
            {
                get;
                private set;
            }
        }

        /// <summary>
        /// A production is simple BNF rule with minor restrictions.
        /// </summary>
        class Production : OwnedItem<Parser>, IProduceEBNF 
        {
            #region BNF
            /// <summary>
            /// Get the type of the AST node this production produces, that is, get the left side of
            /// the BNF rule.
            /// </summary>
            public readonly Type NodeType;
            /// <summary>
            /// Get the default constructor for <see cref="NodeType"/>
            /// </summary>
            private readonly ConstructorInfo DefaultConstructor;
            /// <summary>
            /// Get the grammar to apply to the AST node, that is, get the right side of the BNF rule.
            /// </summary>
            private readonly List<GrammarPart> Grammar;
            #endregion

            #region Properties
            /// <summary>
            /// Get, whether this production is an alternation. That is, the <see cref="NodeType"/>
            /// is abstract and parsing it will yield a well-defined non-abstract sub-class.
            /// </summary>
            private bool IsAlternation
            {
                get
                {
                    return NodeType.IsAbstract;
                }
            }

            /// <summary>
            /// Get EBNF (Extended Backus-Naur Form).
            /// </summary>
            public string EBNF
            {
                get
                {
                    StringBuilder result = new StringBuilder(NodeType.Name);                    
                    result.Append(" ::= ");
                    if (IsAlternation)
                    {
                        result.Append("( ");
                        result.Append(string.Join(" | ", Owner.AlternationsOf(NodeType).ToList().ConvertAll<string>((x) => x.NodeType.Name).ToArray()));
                        result.Append(" )");
                    }
                    else
                    {
                        result.Append(string.Join(" ", Grammar.ConvertAll<string>((g) => g.EBNF).ToArray()));
                    }
                    return result.ToString();                         
                }
            }
			
			/// <summary>
			/// Calculates the terminals.
			/// </summary>
			/// <param name='terminals'>
			/// Terminals.
			/// </param>
			internal void CalculateTerminals(HashSet<TerminalAttribute> terminals)
			{
				if (Grammar != null)
					foreach (var grammar in Grammar)
						grammar.CalculateTerminals(terminals);

			}
            #endregion

            /// <summary>
            /// Create a new instance of the production that describes how to create a certain
            /// AST node. The grammar for this will be retrieved from the type via reflection.
            /// </summary>
            /// <param name="parser">The parser that owns this.</param>
            /// <param name="nodeType">The type of the AST node produced by this.</param>
            internal Production(Parser parser, Type nodeType)
                : base(parser)
            {
                if (parser == null)
                    throw new ArgumentNullException("parser");
                if (nodeType == null)
                    throw new ArgumentNullException("nodeType");

                NodeType = nodeType;
                if (IsAlternation)
                {
                    DefaultConstructor = null;
                    Grammar = null;
                }
                else
                {
                    DefaultConstructor = NodeType.GetConstructor(Type.EmptyTypes);
                    if (DefaultConstructor == null)
                        throw new ParserException(ParserErrorType.MissingConstructor, NodeType);

                    // Get the properties that stand for the grammar
                    Grammar = NodeType.GetProperties().Where((p) => Attribute.IsDefined(p, typeof(GrammarEntityAttribute), true)).ToList().ConvertAll<GrammarPart>((p) => new GrammarPart(this, p));

                    if (Grammar.Count > 0 && Grammar.All((part) => part.IsOptional))
                        throw new ParserException(ParserErrorType.EpsilonDetected, NodeType);
                }
            }

            /// <summary>
            /// Get, whether this type can serve a certain alternation construct.
            /// </summary>
            /// <param name="t">An abstract type.</param>
            /// <returns>true iff <see cref="NodeType"/> derives the abstract type and is not abstract itself.</returns>
            internal bool CanServeAlternation(Type t)
            {
                return !IsAlternation && t.IsAssignableFrom(NodeType);
            }

            private HashSet<TerminalAttribute> m_ExpectedTerminals;
            /// <summary>
            /// Get the set of terminals that indicate that this production should be used. For example,
            /// an block might need to have "Block" as its first keyword.
            /// </summary>
            internal HashSet<TerminalAttribute> ExpectedTerminals
            {
                get
                {
                    if (m_ExpectedTerminals == null)
                    {
                        using (new DetectLeftRecursion(this))
                        {
                            var expectedTerminals = new HashSet<TerminalAttribute>();
                            if (IsAlternation)
                            {
                                foreach (var production in Owner.AlternationsOf(NodeType))
                                {
                                    foreach (var terminal in production.ExpectedTerminals)
                                        if (!expectedTerminals.Add(terminal))
                                        {
                                            // the indicators NEED be unique for the language to be LL(1)
                                            throw new ParserException(ParserErrorType.ExpectedTerminalsNotUnique, NodeType, terminal, production.NodeType);
                                        }
                                }
                            }
                            else
                            {
                                // Walk the lefthand side grammer.
                                for (int part = 0; part < Grammar.Count; part++)
                                {
                                    var grammar = Grammar[part];
                                    // Add all indicator terminals of the first/second/... production
                                    foreach (var terminal in grammar.ExpectedTerminals)
                                        if (!expectedTerminals.Add(terminal))
                                        {
                                            // the indicators NEED be unique for the language to be LL(1)
                                            throw new ParserException(ParserErrorType.ExpectedTerminalsNotUnique, NodeType, terminal, grammar.Property.Name);
                                        }
                                    // If the grammar part is optional, than the next grammar part would
                                    // also be a possible first resolution and we have to take that ones expected terminals
                                    // as well.
                                    if (grammar.IsOptional)
                                        continue;
                                    else
                                        break;
                                }
                            }
                            m_ExpectedTerminals = expectedTerminals;
                        }
                        // A production MUST have at least one expected terminal, otherwise we would have no
                        // way of determining whether the production should be applied or not.
                        if (m_ExpectedTerminals.Count == 0)
                            throw new ParserException(ParserErrorType.NoExpectedTerminals, NodeType);
                    }
                    return m_ExpectedTerminals;
                }
            }
			
			/// <summary>
			/// Determines whether a (hopefully) boolean property is true.
			/// </summary>
			/// <returns>
			/// <c>true</c> if the specified property exists, is boolean, and set to true.
			/// </returns>
			/// <param name='node'>
			/// The node to check.
			/// </param>
			/// <param name='propertyName'>
			/// The name of the property to check.
			/// </param>
			private bool IsBooleanPropertyTrue(INode node, string propertyName)
			{
				var propertyInfo = node.GetType().GetProperty(propertyName);
				
				return
					propertyInfo != null &&
					propertyInfo.PropertyType == typeof(Boolean) &&
					Convert.ToBoolean(propertyInfo.GetValue(node, null));						
			}
			
            /// <summary>
            /// Parse an instance of <see cref="NodeType"/> from the scanner.
            /// </summary>
            /// <param name="scanner">The scanner to use.</param>
            /// <param name="parent">The AST parent of the node to parse. null for root.</param>
            /// <returns>The created instance.</returns>
            internal INode Parse(IScanner scanner, INode parent)
            {
                if (IsAlternation)
                {
                    foreach (var production in Owner.AlternationsOf(NodeType))
                    {
                        if (scanner.CanConsume(production.ExpectedTerminals))
                            return production.Parse(scanner, parent);
                    }
                    throw new ParserException(scanner, ExpectedTerminals);
                }
                else
                {
                    // Create an instance first
                    INode result = DefaultConstructor.Invoke(new object[0]) as INode;

                    // Support the ISupportInitialize interface! Cool feature warning!!
                    using (new Initialize(result))
                    {
                        // Setup the instance.
                        result.LineStart = scanner.Line;
                        result.ColumnStart = scanner.Column;
                        result.Parent = parent;
						
						// Foreach grammar part, remember whether it has been parsed correctly.
						// This is needed to implement property grouping.
						// Key: Name of a property
						// Value: true if parsed successfully, false if skipped because it is optional.
						var parsingMemory = new Dictionary<string, bool>(Grammar.Count);

                        // Apply the parts of the grammar to set the properties of the instance.
                        for (int part = 0; part < Grammar.Count; part++)
                        {
                            var grammar = Grammar[part];
							
							if (!grammar.IsDependant || // Ungrouped rules MUST be parsed
							    (parsingMemory.ContainsKey(grammar.DependsOnProperty) &&
								 parsingMemory[grammar.DependsOnProperty] == true) || // Grouped rules parse conditionally
								IsBooleanPropertyTrue(result, grammar.DependsOnProperty)) 
							{
								parsingMemory[grammar.Property.Name] = grammar.Parse(scanner, result);
							}
                        }

                        // Setup the instance.
                        result.LineEnd = scanner.Line;
                        result.ColumnEnd = scanner.Column;
                    }

                    // Return the parsed node.
                    return result;
                }
            }
        }

        /// <summary>
        /// Wrap objects with this context when initializing them.
        /// </summary>
        class Initialize : IDisposable
        {
            /// <summary>
            /// The item to track.
            /// </summary>
            private readonly ISupportInitialize Item;

            /// <summary>
            /// Create a new context on an entity. If the entity is an ISupportInitialize, call BeginInit()
            /// </summary>
            /// <param name="entity">The entity to initialize.</param>
            public Initialize(object entity)
            {
                Item = entity as ISupportInitialize;
                if (Item != null)
                    Item.BeginInit();
            }

            /// <summary>
            /// Dispose
            /// </summary>
            public void Dispose()
            {
                if (Item != null)
                    Item.EndInit();
            }
        }

        /// <summary>
        /// This class is used to detect left-recursion issues.
        /// </summary>
        class DetectLeftRecursion : IDisposable
        {
            /// <summary>
            /// Get the rule where to detect left recursion.
            /// </summary>
            private readonly Production Rule;

            /// <summary>
            /// Get the outermost DetectLeftRecursion.Rule - this is used for detection.
            /// </summary>
            private static Production RootRule;

            /// <summary>
            /// Create a new instance and check for left-recursion.
            /// </summary>
            /// <param name="rule">The rule to safely deal with.</param>
            public DetectLeftRecursion(Production rule)
            {
                Rule = rule;
                if (RootRule == null)
                {
                    RootRule = Rule;
                }
                else
                {
                    if (RootRule == Rule)
                        throw new ParserException(ParserErrorType.LeftRecursionDetected, Rule.NodeType);
                }
            }

            /// <summary>
            /// Cleanse.
            /// </summary>
            public void Dispose()
            {
                if (RootRule == Rule)
                    RootRule = null;
            }
        }

        /// <summary>
        /// A grammar part is a single part of a BNF right side, like the D? in A => B C* D? E;
        /// A grammar part is responsible for stuffing pars child AST into the property of the parent
        /// AST node.
        /// </summary>
        class GrammarPart : OwnedItem<Production>, IProduceEBNF 
        {
            #region BNF
            /// <summary>
            /// Get the property of the parent AST node this grammar part produces.
            /// </summary>
            public readonly PropertyInfo Property;
            /// <summary>
            /// Get the grammar attribute that defines how parsing takes place.
            /// </summary>
            private readonly GrammarEntityAttribute Grammar;

            /// <summary>
            /// Get EBNF (Extended Backus-Naur Form).
            /// </summary>
            public string EBNF
            {
                get
                {
                    StringBuilder result = new StringBuilder();
                    if (IsSet)
                    {
                        if (!IsOptional)
                        {
                            result.Append(ProducedEntity.Name);
                            result.Append(" ");
                        }

                        result.Append("{ ");
                        result.Append(ProducedEntity.Name);
                        result.Append(" }");
                    }
                    else
                    {
                        if (Grammar is IProduceEBNF)
                        {
                            result.Append(((IProduceEBNF)Grammar).EBNF);
                        }
                        else
                        {
                            if (IsTerminal)
                                result.Append(Grammar);
                            else
                                result.Append(ProducedEntity.Name);
                        }
                        if (IsOptional)
                            result.Append('?');
                    }
                    return result.ToString();
                }
            }

            #endregion

            /// <summary>
            /// Create a new instance.
            /// </summary>
            /// <param name="production">The production of which this instance is a part.</param>
            /// <param name="property">The property of the AST parent that this part resolves.</param>
            internal GrammarPart(Production production, PropertyInfo property)
                : base(production)
            {
                Property = property;
                Grammar = (GrammarEntityAttribute)Attribute.GetCustomAttribute(property, typeof(GrammarEntityAttribute), true);
            }

            /// <summary>
            /// Get, whether this grammar part is optional. In BNF, this would be A? or A*
            /// </summary>
            internal bool IsOptional { get { return Grammar.IsOptional; } }
			
			/// <summary>
			/// Gets a value indicating whether this instance takes part in property grouping.
			/// If the property we depend on has not been parsed, then this rule can be
			/// skipped as well.
			/// </summary>
			/// <value>
			/// <c>true</c> if this instance is dependant; otherwise, <c>false</c>.
			/// </value>
			internal bool IsDependant { get { return !string.IsNullOrEmpty(Grammar.DependsOn); } }
			
			/// <summary>
			/// Gets the name of the property the parsing via this instance depends on.
			/// </summary>
			/// <value>
			/// The name of the property this rule depends on. null, if this property does
			/// not take part in property grouping. For details, see <see cref="IsDependant"/>
			/// </value>
			internal string DependsOnProperty { get { return Grammar.DependsOn; } }
			
            /// <summary>
            /// Get, whether we can write data to the property or not.
            /// </summary>
            private bool CanWrite
            {
                get
                {
                    if (!Property.CanWrite)
                        return false;
                    if (typeof(ISourcePart).IsAssignableFrom(PropertyType))
                        return true;
                    if (IsTerminal && (Grammar as TerminalAttribute).Ignore)
                        return false;
                    return true;                        
                }
            }
            /// <summary>
            /// Get, whether this grammar part resolves a terminal. Grammar parts that are terminals directly
            /// resolve source input.
            /// </summary>
            internal bool IsTerminal { get { return Grammar is TerminalAttribute; } }
					
			/// <summary>
            /// Get, whether this grammar part models a set. In BNF, this would be A* and A+.
            /// </summary>
            private bool IsSet
            {
                get
                {
                    return
                        typeof(IEnumerable).IsAssignableFrom(PropertyType) && PropertyType.IsGenericType
                        || PropertyType.IsArray;
                }
            }
            /// <summary>
            /// Get the type of the property that is produced by this grammar rule.
            /// </summary>
            private Type PropertyType
            {
                get
                {
                    return Property.PropertyType;
                }
            }
            /// <summary>
            /// Get, whether <see cref="PropertyType"/> denotes an array.
            /// </summary>
            private bool IsArray { get { return PropertyType.IsArray; } }

            private Type m_ProducedEntity;
            /// <summary>
            /// Get the type of entity contained in this rule. This would yield A from A, A?, A+, A*
            /// </summary>
            private Type ProducedEntity
            {
                get
                {
                    if (m_ProducedEntity == null)
                    {
                        if (IsSet)
                        {
                            if (IsArray)
                                m_ProducedEntity = PropertyType.GetElementType();
                            else
                                m_ProducedEntity = PropertyType.GetGenericArguments()[0];
                        }
                        else
                        {
                            m_ProducedEntity = PropertyType;
                        }
                    }
                    return m_ProducedEntity;
                }
            }

            private HashSet<TerminalAttribute> m_ExpectedTerminals;
            /// <summary>
            /// Get the set of terminals that indicated that this grammar part should be applied.
            /// </summary>
            internal HashSet<TerminalAttribute> ExpectedTerminals
            {
                get
                {
                    if (m_ExpectedTerminals == null)
                    {
                        m_ExpectedTerminals = new HashSet<TerminalAttribute>();
                        if (IsTerminal)
                        {
                            // If this grammar part is a terminal, then this terminal is definitely expected.
                            m_ExpectedTerminals.Add(Grammar as TerminalAttribute);
                        }
                        else
                        {
                            // If this grammar part is a production, then get the information from the produced entity.
                            m_ExpectedTerminals = Owner.Owner[ProducedEntity].ExpectedTerminals;
                        }
                    }
                    return m_ExpectedTerminals;
                }
            }
			
			/// <summary>
			/// Calculates the terminals in this instance.
			/// </summary>
			/// <param name='terminals'>
			/// Terminals.
			/// </param>
			internal void CalculateTerminals(HashSet<TerminalAttribute> terminals)
			{
				if (IsTerminal)
					terminals.Add(Grammar as TerminalAttribute);
			}

					
            /// <summary>
            /// Set the value of the property.
            /// </summary>
            /// <param name="entity">The entity for which to set the property.</param>
            /// <param name="value">The value to set.</param>
            private void SetValue(INode entity, object value)
            {
                Property.SetValue(entity, value, null);
            }

            /// <summary>
            /// Parse the child AST tree.
            /// </summary>
            /// <param name="scanner">The scanner to use.</param>
            /// <param name="entity">The parent AST node.</param>
            /// <returns>true, if something was parsed, false, if no match was found but the rule was optional.</returns>
            internal bool Parse(IScanner scanner, INode entity)
            {
                // Step 1: Do we match?
                if (!scanner.CanConsume(ExpectedTerminals))
                {
                    // No match? If we are optional, then that's fine! Otherwise the input does not match syntax.
                    if (!IsOptional)
                        throw new ParserException(scanner, ExpectedTerminals);
                    else
                    {
                        if (CanWrite)
                            // Initialize stuff to null / default(T)
                            SetValue(entity, PropertyType.IsValueType ? Activator.CreateInstance(PropertyType) : null);
                    }                    
					return false;
                }
                else
                {
					#region Match successful
                    // Step 2: Consume match!
                    if (IsTerminal)
                    {
                        // Consume a terminal.
                        // We support:
                        //		- any property of type IConvertible (bool, int, string, ...)
                        //		- properties of type Object
                        //		- properties of  a type that has a constructor accepting a string parameter.
                        var lineStart = scanner.Line;
                        var columnStart = scanner.Column;
                        object propertyValue = scanner.Consume().MatchedString;
                        var lineEnd = scanner.Line;
                        var columnEnd = scanner.Column;

                        if (CanWrite)
                        {
                            if (typeof(IConvertible).IsAssignableFrom(PropertyType))
                            {
                                // Use the IConvertible capabilities
                                propertyValue = Convert.ChangeType(propertyValue, PropertyType);
                            }
                            else
                            {
                                // Does the custom type offer a constructor with parameter string that we could use?
                                var stringConstructor = PropertyType.GetConstructor(new Type[] { typeof(string) });
                                if (stringConstructor != null)
                                    // If yes, use that constructor!
                                    propertyValue = stringConstructor.Invoke(new object[] { propertyValue });
                            }

                            if (propertyValue is ISourcePart)
                            {
                                using (new Initialize(propertyValue))
                                {
                                    var sourcePart = propertyValue as ISourcePart;
                                    sourcePart.LineStart = lineStart;
                                    sourcePart.ColumnStart = columnStart;
                                    sourcePart.LineEnd = lineEnd;
                                    sourcePart.ColumnEnd = columnEnd;
                                }
                            }

                            SetValue(entity, propertyValue);
                        }
                    }
                    else
                    {
                        // Recurse: Construct entities recursively
                        if (IsSet)
                        {
                            // For sets: Create a temporary ordered set of child elements.
                            // BNF: A => B* or A => B+
                            IList eSet = Activator.CreateInstance(typeof(List<>).MakeGenericType(ProducedEntity)) as IList;
                            do
                            {
                                // Parse next child
                                eSet.Add(Owner.Owner[ProducedEntity].Parse(scanner, entity));
                                // Try to find another child.
                            }
                            while (scanner.CanConsume(ExpectedTerminals));
                            // Get the current value of the collection.
                            ICollection set = Property.GetValue(entity, null) as ICollection;

                            bool mustFillList;
                            // Could we use existing property value?
                            // Imagine the following:
                            // [Production]
                            // public List<Block> Blocks { get; }
                            // --> if Blocks is not null, then we could just fill the existing list!
                            if (IsArray || (set as IList) == null)
                            {
                                // Arrays
                                if (IsArray)
                                {
                                    // The property is an array: We need to set it as a whole!
                                    set = Array.CreateInstance(ProducedEntity, eSet.Count);
                                    mustFillList = false;
                                    for (int i = 0; i < eSet.Count; i++)
                                        (set as Array).SetValue(eSet[i], i);
                                }
                                // Typed list/collection/enumerable: Can we use our temporary list to assign it directly?
                                else if (PropertyType.IsAssignableFrom(eSet.GetType()))
                                {
                                    set = eSet;
                                    mustFillList = false;
                                }
                                // Custom collections
                                else
                                {
                                    // There must be a custom collection type. We need to instantiate it.
                                    set = (IList)Activator.CreateInstance(PropertyType);
                                    mustFillList = true;
                                }
                                SetValue(entity, set); // Set list
                            }
                            else
                            {
                                mustFillList = true; // Reuse existing list, just fill it!
                            }

                            if (!IsArray && mustFillList)
                            {
                                // Fill ILists
                                IList listSet = (IList)set;
                                using (new Initialize(listSet))
                                {
                                    listSet.Clear();
                                    foreach (var node in eSet)
                                        listSet.Add(node);
                                }
                            }
                        }
                        else
                        {
                            // Single entities: Simply recurse
                            SetValue(entity, Owner.Owner[ProducedEntity].Parse(scanner, entity));
                        }
                    }
					#endregion
					return true;
                }
            }
			
        }
    }
}
